package nl.saxion.act.bus;

import java.util.ArrayList;
import java.util.List;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;

import nl.saxion.act.gameframework.WorldView;
import nl.saxion.act.logging.Assert;

public class Bus extends BuswereldItem {
    private final int      nummer;
    private final int      maxPassagiers;
    private boolean        gestart       = false;
    private double         snelheid      = 0.0;
    private boolean        deurOpen      = true;
    private Locatie        locatie       = new Locatie( 0, 0 );
    private List<Reiziger> passagiers    = new ArrayList<Reiziger>();
	
	public Bus( int busNr, int maxAantalPassagiers, int x, int y , Buswereld world ) {
		super( x, y, world, Buswereld.TILE_TYPES.BUS );
		
        Assert.check( busNr               >  100, "busnummer < 100 (" + busNr + ")"                    );
        Assert.check( busNr               < 1000, "busnummer >= 1000" + busNr + ")"                    );
        Assert.check( maxAantalPassagiers >    0, "maxpassagiers <= 0 ("   + maxAantalPassagiers + ")" );
        Assert.check( maxAantalPassagiers <   64, "maxpassagiers >= 64 ("  + maxAantalPassagiers + ")" );
        
        nummer = busNr;
        maxPassagiers = maxAantalPassagiers;
        setWorldPositionToLocation();
	}
  
    public int     getNummer()        { return nummer;        }
    public int     getMaxPassagiers() { return maxPassagiers; }
    public double  getSnelheid()      { return snelheid;      }
    public Locatie getLocatie()       { return locatie;       }
    public boolean isDeurOpen()       { return deurOpen;      }
    public boolean isGestart()        { return gestart;       }
    
    
    public void start()
    {
		Assert.check( ! gestart,     "de bus was al gestart"         );
        Assert.check( snelheid == 0, "kan geen rijdende bus starten" );  // Probably superfluous
        gestart = true;
    }
    
    public void versnel()
    {
        Assert.check( gestart,         "de bus moet eerst gestart worden" );
        Assert.check( snelheid == 0.0, "de bus reed al op die snelheid"   );
        Assert.check( ! deurOpen,      "mag niet rijden met de deur open" );
        snelheid = 10; // kmh
    }

    public void rem() 
    {
        Assert.check( snelheid != 0, "snelheid is al 0, kan niet meer stoppen" );
        Assert.check( ! deurOpen,    "mag niet stoppen met de deur al open"    );
        snelheid = 0;
    }
    
    public void stop()
    {
        Assert.check( snelheid == 0, "mag de bus alleen stoppen als de snelheid 0 is" );
        gestart = false;
    }

    public void sluitDeur()
    {
        Assert.check( deurOpen,      "deur was al gesloten" );
        Assert.check( snelheid == 0, "de deur mag niet worden gesloten tijdens het rijden" );
        deurOpen = false;
    }
    
    public void openDeur()
    {
        Assert.check( ! deurOpen,    "deur was al geopend" );
        Assert.check( snelheid == 0, "de deur mag niet worden geopend tijdens het rijden" );
        deurOpen = true;
    }
    
    public int getAantalPassagiers()
    {
        return passagiers.size();
    }
    
    public boolean isVol()
    {
        return passagiers.size() >= maxPassagiers;
    }
    
    public void add( Reiziger reiziger ) 
    {
    	Assert.check( deurOpen,                          "je kan alleen door een open deur instappen" );
        Assert.check( reiziger != null,                  "reiziger mag niet null zijn"                );
        Assert.check( ! passagiers.contains( reiziger ), "reiziger zit al in de bus"                  );
        Assert.check( ! isVol(),                         "er is geen ruimte meer voor een reiziger"   ); 
        
        passagiers.add( reiziger );
     }
    
    public void remove( Reiziger passagier ) 
    {
    	Assert.check( deurOpen,                         "je kan alleen door een open deur uitstappen" );
        Assert.check( passagier != null,                "Passagier mag niet null zijn"                );
        Assert.check( passagiers.contains( passagier ), "passagier ziet niet in de bus"               );

        passagiers.remove( passagier );
    }
    
    public List<Reiziger> getPassagiers()
    {
        Assert.check( passagiers != null, "er is geen passagiers lijst" );
        return new ArrayList<Reiziger>( passagiers );
    }
    
    public void rijRichting( Locatie nieuweLocatie )
    {
        Assert.check( gestart,                           "De bus is nog niet gestart en kan dus niet rijden" );
        Assert.check( snelheid > 0,                      "de bus staat nog stil"                             );
        Assert.check( ! deurOpen,                        "de deur is nog open"                               );
        Assert.check( ! locatie.equals( nieuweLocatie ), "bus is al ter plekke"                              );

        double verschilX = nieuweLocatie.x - locatie.x;
        double verschilY = nieuweLocatie.y - locatie.y;
        
        double afstand = Math.sqrt( verschilX * verschilX + verschilY * verschilY );
        
        double verplaatsingX = verschilX / afstand;
        double verplaatsingY = verschilY / afstand;
        double afgelegdeAfstand = Math.sqrt( verplaatsingX * verplaatsingX + verplaatsingY * verplaatsingY );
        
        // TODO uitzoeken waarom er hier een afrondfout komt
        if ( afstand > BusActor.MAXIMUM_TE_RIJDEN_AFSTAND_PER_STAP + 0.00001 ) {
            Assert.check( false, "oops, programmeerfout, afstand=" + afstand + "afgelegdeAfstand=" + afgelegdeAfstand );
            locatie = new Locatie( this.locatie.x + verplaatsingX, this.locatie.y + verplaatsingY );
        } else {
            locatie = nieuweLocatie;
        }
        setWorldPositionToLocation();
    }
    
    private void setWorldPositionToLocation() {
		int halfWidth =  bitmap.getWidth()  / 4;
		int height    =  bitmap.getHeight() / 2;
		int x = (int) locatie.x;
		int y = (int) locatie.y;
		position.set( x - halfWidth, y - height, x + halfWidth, y );
	}

	public void draw( Canvas canvas, WorldView worldView ) {
		super.draw( canvas, worldView );
		
		Buswereld busWorld = (Buswereld) worldView.getWorld();
		Bitmap reiziger    = busWorld.getBitmap( Buswereld.TILE_TYPES.REIZIGER );

		Rect positionInWorld = new Rect( -reiziger.getWidth(), -reiziger.getHeight() * 3, reiziger.getWidth() * 2 , 0 );
		positionInWorld.offset( position.centerX(), position.bottom  );
		for ( int i = passagiers.size() ; i > 0 ; i-- ) {
			positionInWorld.offset( 30, 0 );
			worldView.drawBitmap( reiziger, positionInWorld, canvas );
		}
	}
}
